import { pull, push } from '@/utils/fp';
import { createNextTickOnce } from '@/utils/index';

class PubSub {
  value = null;

  listeners = [];

  constructor(shouldUpdate) {
    if (typeof shouldUpdate === 'function') {
      this.shouldUpdate = shouldUpdate;
    }
  }

  shouldUpdate = () => true;

  sub = (fn) => {
    this.listeners = push(fn)(this.listeners);
    return () => {
      this.listeners = pull(fn)(this.listeners);
    };
  };

  update = (val) => {
    if (!this.shouldUpdate(val, this.value)) return;
    this.value = val;
    return this.publishOnce();
  };

  publish = () => {
    for (const fn of this.listeners) {
      try {
        fn?.(this.value);
      } catch {}
    }
  };

  publishOnce = createNextTickOnce(this.publish);
}

export default PubSub;
